package org.msn.server.handler;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.msn.config.RoomInfo;
import org.msn.rest.RestResult;
import org.msn.server.database.Repository;
import org.msn.util.JsonUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public abstract class RequestHandler extends SimpleChannelInboundHandler<String> {
    protected final static Map<String, RoomInfo> ROOMS = new ConcurrentHashMap<>();

    protected final Repository repository;

    protected RequestHandler(Repository repository) {
        this.repository = repository;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端 " + ctx.channel().remoteAddress() + " 存活");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("收到客户端" + ctx.channel().remoteAddress() + "发送的消息：" + JsonUtil.formJson(msg, RestResult.class));

        // 获得请求数据
        RestResult restResult = JsonUtil.formJson(msg, RestResult.class);
        // 解析请求数据
        parse(ctx, restResult);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
//        String message = msg;
//        if ("ping".equals(message)) {
//            log.info(ctx.channel().remoteAddress() + "===>server: " + message);
//            ctx.write("pong");
//            ctx.flush();
//        }
    }

//    /**
//     * 五秒内没有读请求 向客户端发送心跳
//     * @param ctx
//     * @param evt
//     * @throws Exception
//     */
//    @Override
//    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//        if (evt instanceof IdleStateEvent) {
//            IdleStateEvent event = (IdleStateEvent) evt;
//            if (IdleState.READER_IDLE.equals((event.state()))) {
//                ctx.writeAndFlush("ping").addListener(ChannelFutureListener.CLOSE_ON_FAILURE) ;
//            }
//        }
//        super.userEventTriggered(ctx, evt);
//    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("服务器已接受", CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("客户端 " + ctx.channel().remoteAddress() + " 连接已关闭");
        log.info(cause.toString());
//        channelHandlerContextList.remove(ctx);
        ctx.close();
    }

    /**
     * 解析请求调用相应的方法
     * @param ctx
     * @param restResult
     */
    public void parse(ChannelHandlerContext ctx, RestResult restResult) {
        try {
            getMethodByMethodName(restResult.getMsg()).invoke(this, ctx, restResult.getData());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    private Method getMethodByMethodName(String methodName) throws NoSuchMethodException {
        Method method = getClass().getDeclaredMethod(methodName, ChannelHandlerContext.class, Object.class);
        method.setAccessible(true);
        return method;
    }

    /**
     * 这里的设计可以理解为所有的人
     * 无论怎么聊天都是在一个聊天组内交流
     * @param ctx
     * @param data
     */
    protected abstract void sendMsg(ChannelHandlerContext ctx, Object data);
    protected abstract void getAllRoom(ChannelHandlerContext ctx, Object data);
    protected abstract void createRoom(ChannelHandlerContext ctx, Object data);
    protected abstract void joinRoom(ChannelHandlerContext ctx, Object data);
    protected abstract void leaveRoom(ChannelHandlerContext ctx, Object data);
    protected abstract void closeConnection(ChannelHandlerContext ctx, Object data);
    protected abstract void getRoomAllUserIP(ChannelHandlerContext ctx, Object data);
    protected abstract void openVideo(ChannelHandlerContext ctx, Object data);
    protected abstract void openSound(ChannelHandlerContext ctx, Object data);
}
